﻿namespace ReplayDataFile
{
    using System;
    using System.Collections.Generic;

    internal class CachedRecordInfo
    {
        private BlockFileReader bfReader;
        private List<DataRecord> cachedRecordList = new List<DataRecord>();
        public Dictionary<int, DataTypeCachedInfo> ChachedDataTypes = new Dictionary<int, DataTypeCachedInfo>();
        public long CurRecordNo;
        private int readCount;

        public CachedRecordInfo(BlockFileReader bfReader)
        {
            this.bfReader = bfReader;
        }

        internal void AddCacheRecord(DataRecord rec)
        {
            this.cachedRecordList.Add(rec);
        }

        public void Clear()
        {
            this.cachedRecordList.Clear();
            this.ChachedDataTypes.Clear();
            this.CurRecordNo = 0L;
            this.readCount = 0;
        }

        private int GetRemainCachedRecordCount()
        {
            return (this.cachedRecordList.Count - this.readCount);
        }

        private bool IsReadOver()
        {
            foreach (DataTypeCachedInfo info in this.ChachedDataTypes.Values)
            {
                if (!info.IsReadOver())
                {
                    return false;
                }
            }
            return true;
        }

        public List<DataRecord> ReadCacheRecord(int count)
        {
            List<DataRecord> list = new List<DataRecord>();
            int remainCachedRecordCount = this.GetRemainCachedRecordCount();
            if (remainCachedRecordCount < count)
            {
                if (this.readCount > 0)
                {
                    this.cachedRecordList.RemoveRange(0, this.readCount);
                    this.readCount = 0;
                }
                this.ReadRecord2Cahce(count * 3);
                remainCachedRecordCount = this.GetRemainCachedRecordCount();
            }
            if (remainCachedRecordCount >= count)
            {
                list.AddRange(this.cachedRecordList.GetRange(this.readCount, count));
            }
            else
            {
                list.AddRange(this.cachedRecordList.GetRange(this.readCount, remainCachedRecordCount));
            }
            this.readCount += list.Count;
            if (list.Count > 0)
            {
                this.CurRecordNo = list[list.Count - 1].RecordNo + 1L;
            }
            return list;
        }

        private void ReadRecord2Cahce(int count)
        {
            SortedDictionary<long, DataRecord> dictionary = new SortedDictionary<long, DataRecord>();
            long curRecordNo = this.CurRecordNo;
            while (true)
            {
                long maxRecordNo = curRecordNo + count;
                foreach (DataTypeCachedInfo info in this.ChachedDataTypes.Values)
                {
                    List<DataRecord> list = info.ReadCachedRecord(curRecordNo, maxRecordNo);
                    foreach (DataRecord record in list)
                    {
                        dictionary.Add(record.RecordNo, record);
                    }
                }
                curRecordNo = maxRecordNo;
                this.cachedRecordList.AddRange(dictionary.Values);
                if (this.IsReadOver() || (this.cachedRecordList.Count >= count))
                {
                    return;
                }
            }
        }
    }
}

